package com.game.netty;


import com.game.net.Connect;
import com.game.net.ConnectListener;
import com.game.net.NetAddress;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import java.net.InetSocketAddress;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public abstract class NettyConnect<T> extends SimpleChannelInboundHandler<T> implements Connect {
    protected Logger log = LoggerFactory.getLogger(getClass());

    protected ChannelHandlerContext ctx;

    protected NetAddress remoteAddress;

    protected List<ConnectListener> connectListeners = new CopyOnWriteArrayList<>();

    protected long lastHeartbeatTime;

    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        super.channelActive(ctx);
        this.ctx = ctx;
        this.log.debug("创建连接完成，ctx={}", ctx);
        InetSocketAddress address = (InetSocketAddress)ctx.channel().remoteAddress();
        this.remoteAddress = new NetAddress(address.getAddress().getHostAddress(), address.getPort());
        onCreate();
    }

    public void channelRegistered(ChannelHandlerContext ctx) throws Exception {
        super.channelRegistered(ctx);
    }

    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        this.log.debug("tips caught exception,ctx=" + ctx, cause);
        close();
    }

    public boolean write(Object msg) {
        try {
            this.ctx.writeAndFlush(msg).addListener(future -> {
                if (!future.isSuccess()) {
                    Throwable e = future.cause();
                    if (e != null) {
                        e.printStackTrace();
                        this.log.warn("", e);
                    }
                }
            });
        } catch (Exception e) {
            e.printStackTrace();
        }
        return true;
    }

    public boolean isActive() {
        return this.ctx.channel().isActive();
    }

    public NetAddress address() {
        return this.remoteAddress;
    }

    public void close() {
        this.log.debug("服务器主动关闭连接，netAddress={},ctx={}", this.remoteAddress, this.ctx);
        try {
            this.ctx.close();
        } catch (Exception e) {
            this.log.warn("关闭连接异常"+ this.remoteAddress + ",ctx=" + this.ctx, e);
        }
    }

    public void writeAndClose(Object obj) {
        this.log.debug("服务器主动关闭连接并通知，remoteAddress={},ctx={}", this.remoteAddress, this.ctx);
        try {
            this.ctx.writeAndFlush(obj).addListener(future -> {
                if (isActive())
                    this.ctx.close();
            });
        } catch (Exception e) {
            this.log.warn("关闭连接异常，remoteAddress="+ this.remoteAddress + ",ctx=" + this.ctx, e);
        }
    }

    protected void channelRead0(ChannelHandlerContext ctx, T msg) throws Exception {
        messageReceived(msg);
    }

    public void channelUnregistered(ChannelHandlerContext ctx) throws Exception {
        super.channelUnregistered(ctx);
    }

    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
        this.log.debug("channel inactive,ctx={}", ctx);
        this.connectListeners.forEach(connectListener -> connectListener.onConnectClose(this));
        this.connectListeners.clear();
        onClose();
        super.channelInactive(ctx);
    }

    public void addConnectListener(ConnectListener connectListener) {
        this.connectListeners.add(connectListener);
    }

    public void removeConnectListener(ConnectListener connectListener) {
        this.connectListeners.remove(connectListener);
    }

    public String toString() {
        return "NettyConnect{ctx=" + this.ctx + ", remoteAddress=" + this.remoteAddress + '}';
    }

    public abstract void messageReceived(T paramT);
}

